"""
    类提供了一种组合数据和功能的方法。创建一个新类意味着一个新类型的对象，从而允许创建一个该类型的新实例。
    每个类的实例可以拥有保存自己状态的属性。一个类的实例也可以有改变自己状态的方法。

    Python的类提供了面向对象编程的所有标准特性: 类继承机制允许多个基类，派生类可以覆盖它基类的任何方法。
    一个方法可以调用它基类中相同名称的方法。

    在不同时刻创建的命名空间拥有不同的生存期。包含内置名称的命名空间是在 Python 解释器启动时创建的，永远不会被删除。
    模块的全局命名空间在模块定义被读入时创建；通常，模块命名空间也会持续到解释器退出。被解释器的顶层调用执行的语句，从一个
    脚本文件读取或交互式地读取，被认为是__main__模块调用的一部分，因此它们拥有自己的全局命名空间。
    （内置名称实际上也存在于一个模块中；这个模块称作[builtins]。）

"""

def outer_fuc():
    x = 15

    def inner_fuc():
        # 如果不是用nonlocal 那么x将是在inner_fuc新建的一个变量，而不是指的x=15
        nonlocal x
        x = 5
        print(f'inner \'s function value of x is : ', x)

    inner_fuc()
    print(f"Outer function: x = {x}")

outer_fuc()
"""
global 语句可被用来表明特定变量生存于全局作用域并且应当在其中被重新绑定；nonlocal 语句表明特定变量生存于外层作用域中并且应当在其中被重新绑定。
"""
print('\n========================================================\n')
'''
    nonlocal 指定使用此函数外层的变量
    global 指定是本模块最外层的上下文变量
'''
def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)
# After local assignment: test spam
# After nonlocal assignment: nonlocal spam
# After global assignment: nonlocal spam
# In global scope: global spam
print('\n========================================================\n')


class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'


print(MyClass.i)
print(MyClass.f)
x = MyClass()
print(MyClass.f is x.f)
print(MyClass.__doc__)
print('\n========================================================\n')
x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print(x.counter)
del x.counter

print('\n========================================================\n')
class Dog:

    tricks = []             # mistaken use of a class variable

    def __init__(self, name):
        self.name = name

    def add_trick(self, trick):
        self.tricks.append(trick)

d = Dog('Fido')
e = Dog('Buddy')
d.add_trick("roll over")
d.add_trick("play dead")
print(d.tricks) # unexpectedly shared by all dogs
print('\n========================================================\n')
class Dog:

    def __init__(self, name):
        self.name = name
        self.tricks = []    # creates a new empty list for each dog

    def add_trick(self, trick):
        self.tricks.append(trick)

d = Dog('Fido')
e = Dog('Buddy')
d.add_trick('roll over')
e.add_trick('play dead')
print(d.tricks)
print(e.tricks)
print('\n========================================================\n')

"""
   如果同样的属性名称同时出现在实例和类中，则属性查找会优先选择实例
"""
class Warehouse:
    purpose = 'storage'
    region = 'west'


w1 = Warehouse()
print(w1.purpose, w1.region)
# storage
# west
w2 = Warehouse()
w2.region = 'east'
w2.man='man'
print(w2.purpose, w2.region,w2.man)
# storage
# east

print('\n========================================================\n')

# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1

    def g(self):
        return 'hello world'

    h = g

print(C.f(C(),2,-1))
# print(C.h(C()))
print(C().g())

print('\n========================================================\n')
# 判断类型
print("aa".__class__ is str)
print(isinstance("aa", str))
print(type("aa") is str)

print('\n==========================判断类型==============================\n')

"""
Python 有两个内置函数可被用于继承机制：
    1. isinstance()来检查一个实例的类型:isinstance(obj,int)仅会在obj.__class__为int或某个派生自int的类型时为True;
    
    2. issubclass()来检查继承关系: issubclass(bool,int)为True,因为bool是int的子类,但是,issubclass(float,int)为False,
    因为float不是int的子类
    
"""
b:bool = False
print(issubclass(False.__class__, (int, str)))
print(isinstance(False, int))
print('\n========================================================\n')
"""
    多重继承
    Python supports a form of multiple inheritance as well. A class definition with multiple base classes looks like this:
    继承搜索元素是递归深度搜索,从左到右
"""

print('\n========================================================\n')
"""
    私有变量
        那种仅限从一个对象内部访问的私有实例变量在python中并不存在.
        但是大多数python代码都遵循这样一个约定:带有一个下划线的名称(例如: _spam)应该被当作是API的非仅供部分
"""

print('\n========================================================\n')

class Empty():
    pass

e = Empty()
e.read = lambda param: print(param)
e.__self__=e
e.__func__=e.read

def aa(e:Empty):
    e.read("abc")
    print(e.__self__)
    print(e.__func__)

aa(e)


"""


"""
print('\n========================================================\n')
a = "efg"
it = iter(a)
print(next(it))
print(next(it))
print(next(it))
try:
    print(next(it))
except StopIteration as e :
    print("exception msg: ", e)

print('\n========================================================\n')
class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == len(self.data):
            raise StopIteration
        chars = self.data[self.index]
        self.index = self.index + 1
        return chars

rev = Reverse('spam')
for char in rev:
    print(char)

print('\n========================================================\n')


print('\n======================自己编写遍历==================================\n')

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

for char in reverse('golf'):
    print(char)

'''
生成器Generator 是一个创建迭代器的简单而强大的工具.它们的写法类似标准的函数,但当它们要返回数据时会使用yield语句。
每次对生成器调用 next() 时，它会从上次离开位置恢复执行(会记住上次执行语句时的所有数据值)
可以用生成器来完成的操作同样可以用前一节所描述的基于类的迭代器来完成。 但生成器的写法更为紧凑，因为它会自动创建 __iter__() 和 __next__() 方法。

生成器表达式:
    
'''
strs="gold"
print(list(strs[i] for i in range(len(strs) - 1, -1, -1)))
import sys
print(sys.__dict__)
print('\n========================================================\n')